package com.sinosoft.dsp.platform.manager;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.event.ActionEvent;

import com.sinosoft.builder.parser.SinoParserType;
import com.sinosoft.builder.templates.app.AppSetup;
import com.sinosoft.builder.templates.app.ApplicationType;
import com.sinosoft.builder.templates.app.MenuItem;
import com.sinosoft.builder.templates.app.NavigationType;
import com.sinosoft.builder.templates.concept.BusinessConcept;
import com.sinosoft.builder.templates.concept.CodeSet;
import com.sinosoft.builder.templates.concept.Document;
import com.sinosoft.builder.templates.concept.SearchForm;
import com.sinosoft.builder.templates.view.InsertStructureType;
import com.sinosoft.builder.templates.view.LayoutType;
import com.sinosoft.builder.templates.view.PageSetup;
import com.sinosoft.builder.templates.view.SceneType;
import com.sinosoft.builder.templates.view.StructureType;
import com.sinosoft.dsp.persistence.businessconcept.facade.ICodeFacade;
import com.sinosoft.dsp.platform.utils.CodeSetMap;
import com.sinosoft.dsp.platform.utils.SinoManagedBean;
import com.sinosoft.dsp.platform.utils.UserOrgMap;
import com.sinosoft.dsp.system.core.log.Log;
import com.sinosoft.dsp.system.utils.Const;

/**
 * 应用程序建立类<br>
 * 负责解析配置和初始化配置文件
 * 
 * @since 1.0 2009-11-20
 * @author 潘巍（Peter Pan）
 * 
 */
@ManagedBean(name = "applicationBuilder")
@ApplicationScoped
public class ApplicationBuilder implements Serializable {

	private static final long serialVersionUID = -1882302201450561067L;

	private static final Log log = Log.getLog(ApplicationBuilder.class
			.getName());

	/**
	 * 错误信息
	 */
	private List<String> errs = new ArrayList<String>();

	/**
	 * 导航模板对象树的引用
	 */
	private List<AppSetup> apps;

	private Map<String, ApplicationType> applications;

	private Map<String, NavigationType> navigations;

	private Map<String, MenuItem> naviItems;

	/**
	 * 系统页面模板对象树的引用
	 */
	private List<PageSetup> views;
	// 场景元素对象的Map
	private Map<String, SceneType> scenes;

	/**
	 * 业务概念模板对象树的引用
	 */
	// 业务概念根对象
	private BusinessConcept concept;
	// 业务概念元数据（不包含代码表和文书）
	private Map<String, Object> businessConceptMetas;

	// 代码集id与其对象的映射
	private Map<String, CodeSet> codeSets;
	// 代码集id与其树节点集合的映射
	private Map<String, Map<String, ICodeFacade>> codeSetTrees;
	// 代码集idAndType与页面元素对象的映射
	private Map<?, ?> codeSetObject = new CodeSetMap();

	// 人员部门
	private Map<?, ?> userOrgObject = new UserOrgMap();

	// 文书id与其对象的映射
	private Map<String, Document> documents;

	// 查询表单id与其对象的映射
	private Map<String, SearchForm> searchForms;

	public static ApplicationBuilder getInstance() {
		return SinoManagedBean.findBean("applicationBuilder");

	}

	private void clearMetaData() {
		// clear app
		this.apps = null;
		this.applications = null;
		this.navigations = null;
		this.naviItems = null;

		// clear view
		this.views = null;
		this.scenes = null;

		// clear concept
		this.concept = null;
		this.businessConceptMetas = null;
		this.codeSets = null;
		this.codeSetTrees = null;
		this.documents = null;
		this.searchForms = null;
	}

	public void reloadMetaData() {
		clearMetaData();
		loadMetaData();
	}

	public void reloadMetaData(ActionEvent actionEvent) {
		reloadMetaData();
	}

	@PostConstruct
	public void loadMetaData() {
		errs.clear();
		// 应用
		apps = SinoParserType.APP.parser(errs);
		List<String> tmp = SinoParserType.APP.validation(apps);
		if (tmp != null)
			errs.addAll(tmp);

		// 视图
		views = SinoParserType.VIEW.parser(errs);
		tmp = SinoParserType.VIEW.validation(views);
		if (tmp != null)
			errs.addAll(tmp);
		loadView();

		// 业务概念
		List<BusinessConcept> conceptArr = SinoParserType.BUSSINESSCONCEPT
				.parser(errs);
		if (conceptArr.size() == 1) {
			concept = conceptArr.get(0);
		}
		tmp = SinoParserType.BUSSINESSCONCEPT.validationOne(concept);
		if (tmp != null)
			errs.addAll(tmp);

		for (String err : errs) {
			log.error(err);
		}

	}

	/**
	 * 加载视图的附加内容，如：将InsertStructureType插入到指定的view中
	 */
	private void loadView() {
		List<InsertStructureType> insertStructures = new ArrayList<InsertStructureType>();
		for (PageSetup view : views) {
			insertStructures.addAll(view.getInsertStructure());
		}

		for (InsertStructureType ist : insertStructures) {
			for (PageSetup view : views) {
				List<SceneType> sL = view.getScene();
				for (SceneType s : sL) {
					if (!Const.isEmpty(s.getId())
							&& ist.getTargetScene().equals(s.getId())) {
						for (LayoutType l : s.getLayout()) {
							if (!Const.isEmpty(l.getId())
									&& ist.getTargetLayout().equals(l.getId())) {
								// 循环遍历InsertStructureType
								l
										.getStructure()
										.add(
												createStructureTypeByInsertStructureType(ist));
							}
						}
					}
				}
			}
		}
	}

	/**
	 * 通过InsertStructure创建一个Structure
	 * 
	 * @param ist
	 * @return
	 */
	private StructureType createStructureTypeByInsertStructureType(
			InsertStructureType ist) {
		StructureType s = new StructureType();
		s.setId(ist.getId());
		s.setScene(ist.getScene());
		s.setLayout(ist.getLayout());
		s.setDescription(ist.getDescription());
		s.setSingleton(ist.isSingleton());
		s.setAlias(ist.getAlias());
		return s;
	}

	public List<AppSetup> getApps() {
		return apps;
	}

	public void setApps(List<AppSetup> apps) {
		this.apps = apps;
	}

	public Map<String, ApplicationType> getApplications() {
		return applications;
	}

	public void setApplications(Map<String, ApplicationType> applications) {
		this.applications = applications;
	}

	public Map<String, NavigationType> getNavigations() {
		return navigations;
	}

	public void setNavigations(Map<String, NavigationType> navigations) {
		this.navigations = navigations;
	}

	public Map<String, MenuItem> getNaviItems() {
		return naviItems;
	}

	public void setNaviItems(Map<String, MenuItem> naviItems) {
		this.naviItems = naviItems;
	}

	public List<PageSetup> getViews() {
		return views;
	}

	public void setViews(List<PageSetup> views) {
		this.views = views;
	}

	public Map<String, SceneType> getScenes() {
		return scenes;
	}

	public void setScenes(Map<String, SceneType> scenes) {
		this.scenes = scenes;
	}

	public BusinessConcept getConcept() {
		return concept;
	}

	public void setConcept(BusinessConcept concept) {
		this.concept = concept;
	}

	public Map<String, Object> getBusinessConceptMetas() {
		return businessConceptMetas;
	}

	public void setBusinessConceptMetas(Map<String, Object> businessConceptMetas) {
		this.businessConceptMetas = businessConceptMetas;
	}

	public Map<String, CodeSet> getCodeSets() {
		return codeSets;
	}

	public void setCodeSets(Map<String, CodeSet> codeSets) {
		this.codeSets = codeSets;
	}

	public Map<String, Map<String, ICodeFacade>> getCodeSetTrees() {
		return codeSetTrees;
	}

	public void setCodeSetTrees(
			Map<String, Map<String, ICodeFacade>> codeSetTrees) {
		this.codeSetTrees = codeSetTrees;
	}

	public Map<String, Document> getDocuments() {
		return documents;
	}

	public void setDocuments(Map<String, Document> documents) {
		this.documents = documents;
	}

	public Map<String, SearchForm> getSearchForms() {
		return searchForms;
	}

	public void setSearchForms(Map<String, SearchForm> searchForms) {
		this.searchForms = searchForms;
	}

	public Map<?, ?> getCodeSetObject() {
		return codeSetObject;
	}

	public void setCodeSetObject(Map<?, ?> codeSetObject) {
		this.codeSetObject = codeSetObject;
	}

	public Map<?, ?> getUserOrgObject() {
		return userOrgObject;
	}

	public void setUserOrgObject(Map<?, ?> userOrgObject) {
		this.userOrgObject = userOrgObject;
	}

	public List<String> getErrs() {
		return errs;
	}

	@PreDestroy
	public void destroy() {
		clearMetaData();
	}

}
